package com.echo.echovividlive.service.impl;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.json.JSONUtil;
import cn.hutool.jwt.JWT;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.echo.echovividlive.common.UserThread;
import com.echo.echovividlive.domain.dto.FindPasswordDTO;
import com.echo.echovividlive.domain.dto.PageQueryDTO;
import com.echo.echovividlive.domain.dto.PasswordResetVO;
import com.echo.echovividlive.domain.dto.UserRegisterDTO;
import com.echo.echovividlive.domain.entity.Result;
import com.echo.echovividlive.domain.entity.User;
import com.echo.echovividlive.domain.vo.PageVO;
import com.echo.echovividlive.mapper.UserMapper;
import com.echo.echovividlive.service.IUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.echo.echovividlive.utils.TimeUtil;
import jakarta.mail.MessagingException;
import jakarta.mail.internet.MimeMessage;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.dromara.x.file.storage.core.FileInfo;
import org.dromara.x.file.storage.core.FileStorageService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.echo.echovividlive.common.Constants.*;


/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author xiajunjie
 * @since 2024-10-22
 */
@Service
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    private final StringRedisTemplate stringRedisTemplate;

    private final JavaMailSender javaMailSender;

    @Value("${spring.mail.username}")
    private String MAIL_SENDER;

    private final FileStorageService fileStorageService;

    @Value("${dromara.x-file-storage.minio[0].bucket-name}")
    private String AVATAR_BUKET;

    @Value("${dromara.x-file-storage.minio[0].platform}")
    private String AVATAR_PLATFORM;

    @Value("${dromara.x-file-storage.minio[0].end-point}")
    private String MINIO_ADDRESS;

    @Override
    public Result sendVerifyCode(UserRegisterDTO user) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<User>().eq(User::getEmail,user.getEmail());
        User one = this.getOne(queryWrapper);
        if (one!=null){
            return Result.error("邮箱已被注册");
        }
        String existed = stringRedisTemplate.opsForValue().get(user.getEmail());
        if (existed != null) {
            return Result.error("请勿反复提交");
        }
        String verifyCode = RandomUtil.randomNumbers(6);
        user.setVerifyCode(verifyCode);
        // 发送验证码
        if (!sendEmail(user.getEmail(),verifyCode)){
            return Result.error();
        }
        // 临时存入redis
        stringRedisTemplate.opsForValue().set(user.getEmail(), JSONUtil.toJsonStr(user),5, TimeUnit.MINUTES);
        return Result.success("验证码发送成功",null);
    }

    @Override
    public Result active(UserRegisterDTO user) {
        String cacheUser = stringRedisTemplate.opsForValue().get(user.getEmail());
        UserRegisterDTO bean = JSONUtil.toBean(cacheUser, UserRegisterDTO.class);
        String verifyCode = bean.getVerifyCode();
        if(verifyCode==null){
            return Result.error("验证码已失效");
        }
        if (user.getVerifyCode()==null || !verifyCode.equals(user.getVerifyCode())){
            return Result.error("验证码错误");
        }
        if (!user.equals(bean)){
            return Result.error("两次输入信息不一样");
        }
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<User>().eq(User::getEmail,user.getEmail());
        User one = this.getOne(queryWrapper);
        if (one!=null){
            return Result.error("邮箱已被注册");
        }
        // 确定激活写入数据库
        User newUser = User.builder()
                .avatar(RandomUtil.randomEle(DEFAULT_AVATAR_LIST))
                .balance(0)
                .status(true)
                .fansCount(0L)
                .followingCount(0L)
                .nickName(USER_NICK_PREFIX + UUID.randomUUID())
                .createTime(TimeUtil.getCurrentTime())
                .verifyCode(RandomUtil.randomNumbers(6))
                .email(user.getEmail())
                .password(DigestUtil.md5Hex(user.getPassword()))
                .personalSignature(SYSTEM_DEFAULT_SIGNATURE)
                .build();
        this.save(newUser);
        return Result.success();
    }

    @Override
    public Result login(User user) {
        if (user.getEmail() == null || user.getPassword() == null){
            return Result.error("输入信息为空");
        }
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getEmail, user.getEmail()).eq(User::getPassword, DigestUtil.md5Hex(user.getPassword()));
        User one = this.getOne(queryWrapper);
        if (one == null){
            return Result.error("邮箱或密码错误");
        }
        // 生成令牌
        String token = JWT.create()
                .setSigner(JWT_ALGORITHM, JWT_TOKEN_SINGER.getBytes(StandardCharsets.UTF_8))
                .setExpiresAt(new Date(System.currentTimeMillis() + JWT_EXPIRE_SECOND))
                .setPayload("userId", one.getUserId())
                .sign();
        return Result.success("登录成功",token);
    }

    @Override
    @Transactional
    public Result uploadAvatar(MultipartFile avatar) {
        if (avatar==null){
            return Result.error("请上传图片");
        }
        Integer userId = UserThread.getUserId();
        User existed = this.getById(userId);
        String avatarPath = existed.getAvatar();
        FileInfo upload = fileStorageService.of(avatar)
                .setPlatform(AVATAR_PLATFORM)
                .upload();
        // 不是默认头像则删除原头像
        if(ArrayUtil.contains(DEFAULT_AVATAR_LIST,avatarPath)){
            FileInfo fileInfo = new FileInfo()
                    .setPlatform(AVATAR_PLATFORM)
                    .setFilename(avatarPath.substring(avatarPath.lastIndexOf('.')+1));
            fileStorageService.delete(fileInfo);
        }
        User user = User.builder()
                .userId(userId)
                .avatar(MINIO_ADDRESS+'/'+AVATAR_BUKET+upload.getUrl())
                .build();
        if (this.updateById(user)) {
            return Result.success(MINIO_ADDRESS+'/'+AVATAR_BUKET+upload.getUrl());
        }
        return Result.error("头像上传失败");
    }

    @Override
    public Result resetPassword(PasswordResetVO passwordResetVO) {
        if (!Objects.equals(passwordResetVO.getUserId(), UserThread.getUserId())){
            return Result.error();
        }
        User user = this.getById(passwordResetVO.getUserId());
        String currentPwd = DigestUtil.md5Hex(passwordResetVO.getCurrentPassword());
        if (!user.getPassword().equals(currentPwd)){
            return Result.error("原密码输入错误！");
        }
        user.setPassword(DigestUtil.md5Hex(passwordResetVO.getNewPassword()));
        this.updateById(user);
        return Result.success();
    }

    @Override
    public Result uploadAvatarByStream(HttpServletRequest request) throws IOException {

        Integer userId = UserThread.getUserId();
        User existed = this.getById(userId);
//         删除旧头像
//        if (existed.getAvatar()!=null){
//            FileInfo fileInfo = new FileInfo()
//                    .setPlatform(AVATAR_PLATFORM)
//                    .setFilename(existed.getAvatar().substring(existed.getAvatar().lastIndexOf("/")+1));
//            fileStorageService.delete(fileInfo);
//        }
        FileInfo upload = fileStorageService.of(request)
                .setPlatform(AVATAR_PLATFORM)
                //.setSaveFilename(userId+System.currentTimeMillis()+"_avatar.jpg")
                .upload();
        User user = User.builder()
                .userId(userId)
                .avatar(MINIO_ADDRESS+'/'+AVATAR_BUKET+upload.getUrl())
                .build();
        if (this.updateById(user)) {
            return Result.success(MINIO_ADDRESS+'/'+AVATAR_BUKET+upload.getUrl());
        }
        return Result.error("头像上传失败");
    }

    @Override
    public Result findPassword(FindPasswordDTO findPasswordDTO) {
        if(findPasswordDTO==null){
            return Result.error();
        }
        // 根据步骤选择
        switch (findPasswordDTO.getStep()){
            case 1: {
                String email = findPasswordDTO.getEmail();
                String verifyCode = RandomUtil.randomNumbers(6);
                Boolean existed = stringRedisTemplate.opsForValue().setIfAbsent("Find" + email, verifyCode, 5L, TimeUnit.MINUTES);
                if(!existed){
                    return Result.error("请勿重复提交");
                }
                sendEmail(email,verifyCode);
                return Result.success("验证码已发送",null);
            }
            case 2: {
                String verifyCode = findPasswordDTO.getVerifyCode();
                String code = stringRedisTemplate.opsForValue().get("Find" + findPasswordDTO.getEmail());
                if(!code.equals(verifyCode)){
                    return Result.error("验证码错误");
                }
                return Result.success();
            }
            case 3:{
                boolean update = update()
                        .eq("email", findPasswordDTO.getEmail())
                        .set("password", DigestUtil.md5Hex(findPasswordDTO.getPassword())).update();
                return Result.success(update?"更改密码成功,请返回登录页面":"修改失败",null);
            }
            default: return Result.error();
        }
    }

    public Boolean sendEmail(String email,String verifyCode) {
        try {
            MimeMessage mimeMessage = javaMailSender.createMimeMessage();
            MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, true); // 设为true以支持HTML内容
            mimeMessageHelper.setFrom(MAIL_SENDER);
            mimeMessageHelper.setTo(email);
            mimeMessageHelper.setSubject("欢迎使用EchoVivid直播平台");



            // 读取 HTML 文件内容并指定编码为 UTF-8
            InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("static/register.html");
            String htmlTemplate = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);


            // 替换占位符内容
            String htmlContent = htmlTemplate.replace("{{username}}", email)
                    .replace("{{verificationCode}}",verifyCode);

            // 设置邮件内容为HTML格式
            mimeMessageHelper.setText(htmlContent, true);

            javaMailSender.send(mimeMessage);
            return true;
        } catch (MessagingException | IOException e) {
            e.printStackTrace(); // 打印堆栈跟踪以便调试
            return false;
        }
    }
}
